/*
 * ServiceProxyResource.java
 *
 * Created on October 25, 2007, 9:28 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.www.app.edit;

import java.io.StringWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import org.atomojo.app.client.Link;
import org.atomojo.app.client.LinkSet;
import org.atomojo.app.client.XMLRepresentationParser;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.Name;
import org.infoset.xml.util.XMLWriter;
import org.restlet.Client;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.ChallengeResponse;
import org.restlet.data.ChallengeScheme;
import org.restlet.data.Cookie;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Parameter;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.representation.StringRepresentation;

/**
 *
 * @author alex
 */
public class APPProxy extends Restlet
{
   static Map<String,Boolean> standardHeaders = new TreeMap<String,Boolean>();
   static {
      standardHeaders.put("Cookie",Boolean.TRUE);
      standardHeaders.put("Content-Length",Boolean.TRUE);
      standardHeaders.put("Content-Type",Boolean.TRUE);
      standardHeaders.put("Referer",Boolean.TRUE);
      standardHeaders.put("Connection",Boolean.TRUE);
      standardHeaders.put("Accept-Charset",Boolean.TRUE);
      standardHeaders.put("Accept-Encoding",Boolean.TRUE);
      standardHeaders.put("Accept-Language",Boolean.TRUE);
      standardHeaders.put("Accept",Boolean.TRUE);
      standardHeaders.put("User-Agent",Boolean.TRUE);
      standardHeaders.put("Host",Boolean.TRUE);
      standardHeaders.put("If-None-Match", Boolean.TRUE);
   }
   
   static Name WORKSPACE = Name.create("{http://www.w3.org/2007/app}workspace");
   static Name COLLECTION = Name.create("{http://www.w3.org/2007/app}collection");

   String base;
   String username;
   String password;
   
   public APPProxy(Context context)
   {
      super(context);
      base = context.getParameters().getFirstValue("app.url");
      username = null;
      password = null;
      String relation = context.getParameters().getFirstValue("app.link");
      getLogger().info("app.link="+relation);
      if (relation!=null) {
         LinkSet linkSet = (LinkSet)context.getAttributes().get("org.atomojo.www.app.links");
         List<Link> links = linkSet.get(relation);
         if (links!=null && links.size()>0) {
            Link link = links.get(0);
            base = link.getLink().toString();
            username = link.getUsername();
            password = link.getPassword();
         }
      }
   }
   
   public void handle(Request request,Response response)
   {
      String baseURL = base;
      if (baseURL==null) {
         Object o = request.getAttributes().get("app.url");
         if (o!=null) {
            baseURL = o.toString();
         } else {
            getLogger().severe("app.url missing.");
            response.setStatus(Status.SERVER_ERROR_INTERNAL);
            return;
         }
      }
      String remaining = request.getResourceRef().getRemainingPart();
      if (remaining!=null && remaining.startsWith("R")) {
         int q = remaining.indexOf("?");
         if (q>0) {
            remaining = remaining.substring(0,q);
         }
      }
      Reference appRef = new Reference(remaining==null ? baseURL : baseURL+remaining);
      getLogger().info("APP proxy to "+appRef);
      Client client = new Client(getContext().createChildContext(),appRef.getSchemeProtocol());
      client.getContext().getAttributes().put("hostnameVerifier", org.apache.commons.ssl.HostnameVerifier.DEFAULT);
      Request appRequest = new Request(request.getMethod(),appRef);
      if (username!=null) {
         appRequest.setChallengeResponse(new ChallengeResponse(ChallengeScheme.HTTP_BASIC,username,password));
      } else if (request.getChallengeResponse()!=null) {
         appRequest.setChallengeResponse(request.getChallengeResponse());
      }
      appRequest.setEntity(request.getEntity());
      Cookie cookie = request.getCookies().getFirst("I");
      if (cookie!=null) {
         appRequest.getCookies().add(cookie);
      }
      Form headers = (Form)request.getAttributes().get("org.restlet.http.headers");
      if (headers!=null) {
         Form newHeaders = new Form();
         for (Parameter param : headers) {
            String name = param.getName();
            if (standardHeaders.get(name)==null) {
               newHeaders.add(param);;
            }
         }
         appRequest.getAttributes().put("org.restlet.http.headers",newHeaders);
      }
      Response appResponse = client.handle(appRequest);
      headers = (Form)appResponse.getAttributes().get("org.request.http.headers");
      response.setStatus(appResponse.getStatus());
      if (appResponse.getStatus().isSuccess() && (remaining==null || remaining.length()==0)) {
         String path = request.getResourceRef().getPath();
         path = path.substring(0,path.length()-1);
         getLogger().info("Manipulating service document to adjust to path: "+path);
         try {
            XMLRepresentationParser parser = new XMLRepresentationParser();
            Document introspection = parser.load(appResponse.getEntity());
            Iterator<Element> workspaces = introspection.getDocumentElement().getElementsByName(WORKSPACE);
            while (workspaces.hasNext()) {
               Element workspace = workspaces.next();
               Iterator<Element> collections = workspace.getElementsByName(COLLECTION);
               while (collections.hasNext()) {
                  Element collection = collections.next();
                  String href = collection.getAttributeValue("href");
                  if (href!=null) {
                     int pos = href.indexOf("/R");
                     if (pos>=0) {
                        href = path+href.substring(pos);
                        collection.setAttributeValue("href", href);
                     }
                  }
               }
            }
            StringWriter buffer = new StringWriter();
            XMLWriter.writeDocument(introspection, buffer);
            response.setEntity(new StringRepresentation(buffer.toString(),MediaType.APPLICATION_ATOM_SERVICE_XML));
         } catch (Exception ex) {
            response.setStatus(Status.SERVER_ERROR_INTERNAL);
            getLogger().log(Level.SEVERE,"Cannot parse introspection.",ex);
         }
      } else {
         response.setEntity(appResponse.getEntity());
      }
      response.setChallengeRequests(appResponse.getChallengeRequests());
      response.getAttributes().put("org.request.http.headers", headers);
   }
   
}
